////////////////////////////////////////////////////////////////////////////////

#ifndef _SPLAYER_H_
#include "splayer.h"
#endif

////////////////////////////////////////////////////////////////////////////////

#ifndef _MATHFUNCTIONS_H_
#include "mathfunctions.h"
#endif

#ifndef _SHAPESFACTORY_H_
#include "shapesfactory.h"
#endif

#ifndef _SWEAPON_H_
#include "sweapon.h"
#endif

#ifndef _SERVERENGINE_H_
#include "serverengine.h"
#endif

#include <iostream>

////////////////////////////////////////////////////////////////////////////////


// Default player physical constants
const PE::Point defaulPlayerPosition(100, 100);
const PE::Vector defaultPlayerVelocity = {0, 0};
const float defaultPlayerMass = 50;
const float defaultPlayerResistanceCoeff = 0.5;

// Default player constants
const size_t defaultPlayerHitPoints = 100;

////////////////////////////////////////////////////////////////////////////////


SPlayer::SPlayer( int _ID, size_t _hitPoints, const SWeapon& _weapon )
: SGameObject( _ID, defaultPlayerMass,
               ShapesFactory::GetInstance()->GetPlayerShape(),
               defaultPlayerResistanceCoeff ),
  m_Weapon(_weapon),
  m_LastInputTime(0)
{
    SetHitPoints(_hitPoints);
}


////////////////////////////////////////////////////////////////////////////////


SPlayer::~SPlayer()
{
}


////////////////////////////////////////////////////////////////////////////////


SBullet SPlayer::Shoot()
{
    // Return bullet
    return m_Weapon.Shoot( GetID(),
                           GetPosition(),
                           GetShootDirection() );
}


////////////////////////////////////////////////////////////////////////////////


void SPlayer::ProcessInput( size_t _dt )
{
    // Get direction vector
    PE::Vector vec = {0, 0};
    if ( m_ClientInput.IsGoingRight() )
        vec.vx = 1;
    if ( m_ClientInput.IsGoingLeft() )
        vec.vx = -1;

    if ( m_ClientInput.IsGoingDown() )
        vec.vy = 1;
    if ( m_ClientInput.IsGoingUp() )
        vec.vy = -1;

    // Apply impulse to object
    ApplyImpulse(PE::GetDirection(vec), static_cast<double>(_dt) * 0.05);
}


////////////////////////////////////////////////////////////////////////////////


void SPlayer::SetClientInput( const ClientInput& _input, size_t _creationTime )
{
    if (_creationTime > m_LastInputTime)
    {
        // Set user input
        m_ClientInput = _input;

        // Update time border
        m_LastInputTime = _creationTime;
    }
}


////////////////////////////////////////////////////////////////////////////////


void SPlayer::Respawn()
{
    // Set default player state
    SetHitPoints(defaultPlayerHitPoints);
}


////////////////////////////////////////////////////////////////////////////////


PE::Direction SPlayer::GetShootDirection() const
{
    Point mousePosition = m_ClientInput.GetMousePosition();

    PE::Vector movementVector = { mousePosition.x - GetPosition().x,
                                  mousePosition.y - GetPosition().y };
    return PE::GetDirection( movementVector );
}


////////////////////////////////////////////////////////////////////////////////


size_t SPlayer::GetHitPoints() const
{
    return m_HitPoints;
}


////////////////////////////////////////////////////////////////////////////////


void SPlayer::SetHitPoints( size_t _hitPoints )
{
    m_HitPoints = _hitPoints;
}


////////////////////////////////////////////////////////////////////////////////


bool SPlayer::CanShoot( size_t _dt )
{
    m_Weapon.UpdateTime(_dt);

    return m_ClientInput.IsShootPressed() &&
           !m_Weapon.IsReloading();
}


////////////////////////////////////////////////////////////////////////////////


void SPlayer::Collision( PhysicalObject& _obj )
{
    static_cast<SGameObject&>(_obj).CollideWithPlayer(*this);
}


////////////////////////////////////////////////////////////////////////////////


void SPlayer::CollideWithBullet( SBullet& _bullet )
{
    GetEngine().CollideBulletWithPlayer(_bullet, *this);
}


////////////////////////////////////////////////////////////////////////////////
